/* ========================================================================
 * Copyright (c) 2005-2024 The OPC Foundation, Inc. All rights reserved.
 *
 * OPC Foundation MIT License 1.00
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * The complete license agreement can be found here:
 * http://opcfoundation.org/License/MIT/1.00/
 * ======================================================================*/

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Xml;

namespace Opc.Ua.Configuration
{
    /// <summary>
    /// A class that builds a configuration for a UA application.
    /// </summary>
    public class ApplicationConfigurationBuilder : IApplicationConfigurationBuilder
    {
        /// <summary>
        /// Create the application instance builder.
        /// </summary>
        public ApplicationConfigurationBuilder(ApplicationInstance applicationInstance)
        {
            ApplicationInstance = applicationInstance;
        }

        /// <summary>
        /// The application instance used to build the configuration.
        /// </summary>
        public ApplicationInstance ApplicationInstance { get; }

        /// <summary>
        /// The application configuration.
        /// </summary>
        public ApplicationConfiguration ApplicationConfiguration
            => ApplicationInstance.ApplicationConfiguration;

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderGlobalConfiguration SetHiResClockDisabled(
            bool disableHiResClock)
        {
            ApplicationConfiguration.DisableHiResClock = disableHiResClock;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderClientSelected AsClient()
        {
            switch (ApplicationInstance.ApplicationType)
            {
                case ApplicationType.Client:
                case ApplicationType.ClientAndServer:
                    break;
                case ApplicationType.Server:
                    ApplicationInstance.ApplicationType = m_typeSelected
                        ? ApplicationType.ClientAndServer
                        : ApplicationType.Client;
                    break;
                default:
                    throw new ArgumentException("Invalid application type for client.");
            }

            m_typeSelected = true;

            ApplicationConfiguration.ClientConfiguration = new ClientConfiguration();

            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderSecurityOptions AddSecurityConfiguration(
            string subjectName,
            string pkiRoot = null,
            string appRoot = null,
            string rejectedRoot = null)
        {
            pkiRoot = DefaultPKIRoot(pkiRoot);
            appRoot = appRoot == null ? pkiRoot : DefaultPKIRoot(appRoot);
            rejectedRoot = rejectedRoot == null ? pkiRoot : DefaultPKIRoot(rejectedRoot);
            string appStoreType = CertificateStoreIdentifier.DetermineStoreType(appRoot);
            string pkiRootType = CertificateStoreIdentifier.DetermineStoreType(pkiRoot);
            string rejectedRootType = CertificateStoreIdentifier.DetermineStoreType(rejectedRoot);
            ApplicationConfiguration.SecurityConfiguration = new SecurityConfiguration
            {
                // app cert store
                ApplicationCertificate = new CertificateIdentifier
                {
                    StoreType = appStoreType,
                    StorePath = DefaultCertificateStorePath(TrustlistType.Application, appRoot),
                    SubjectName = Utils.ReplaceDCLocalhost(subjectName)
                },
                // App trusted & issuer
                TrustedPeerCertificates = new CertificateTrustList
                {
                    StoreType = pkiRootType,
                    StorePath = DefaultCertificateStorePath(TrustlistType.Trusted, pkiRoot)
                },
                TrustedIssuerCertificates = new CertificateTrustList
                {
                    StoreType = pkiRootType,
                    StorePath = DefaultCertificateStorePath(TrustlistType.Issuer, pkiRoot)
                },
                // Https trusted & issuer
                TrustedHttpsCertificates = new CertificateTrustList
                {
                    StoreType = pkiRootType,
                    StorePath = DefaultCertificateStorePath(TrustlistType.TrustedHttps, pkiRoot)
                },
                HttpsIssuerCertificates = new CertificateTrustList
                {
                    StoreType = pkiRootType,
                    StorePath = DefaultCertificateStorePath(TrustlistType.IssuerHttps, pkiRoot)
                },
                // User trusted & issuer
                TrustedUserCertificates = new CertificateTrustList
                {
                    StoreType = pkiRootType,
                    StorePath = DefaultCertificateStorePath(TrustlistType.TrustedUser, pkiRoot)
                },
                UserIssuerCertificates = new CertificateTrustList
                {
                    StoreType = pkiRootType,
                    StorePath = DefaultCertificateStorePath(TrustlistType.IssuerUser, pkiRoot)
                },
                // rejected store
                RejectedCertificateStore = new CertificateStoreIdentifier
                {
                    StoreType = rejectedRootType,
                    StorePath = DefaultCertificateStorePath(TrustlistType.Rejected, rejectedRoot)
                }
            };
            SetSecureDefaults(ApplicationConfiguration.SecurityConfiguration);

            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderSecurityOptions AddSecurityConfiguration(
            CertificateIdentifierCollection applicationCertificates,
            string pkiRoot = null,
            string rejectedRoot = null)
        {
            pkiRoot = DefaultPKIRoot(pkiRoot);
            rejectedRoot = rejectedRoot == null ? pkiRoot : DefaultPKIRoot(rejectedRoot);
            string pkiRootType = CertificateStoreIdentifier.DetermineStoreType(pkiRoot);
            string rejectedRootType = CertificateStoreIdentifier.DetermineStoreType(rejectedRoot);
            ApplicationConfiguration.SecurityConfiguration = new SecurityConfiguration
            {
                // app cert store
                ApplicationCertificates = applicationCertificates,
                // App trusted & issuer
                TrustedPeerCertificates = new CertificateTrustList
                {
                    StoreType = pkiRootType,
                    StorePath = DefaultCertificateStorePath(TrustlistType.Trusted, pkiRoot)
                },
                TrustedIssuerCertificates = new CertificateTrustList
                {
                    StoreType = pkiRootType,
                    StorePath = DefaultCertificateStorePath(TrustlistType.Issuer, pkiRoot)
                },
                // Https trusted & issuer
                TrustedHttpsCertificates = new CertificateTrustList
                {
                    StoreType = pkiRootType,
                    StorePath = DefaultCertificateStorePath(TrustlistType.TrustedHttps, pkiRoot)
                },
                HttpsIssuerCertificates = new CertificateTrustList
                {
                    StoreType = pkiRootType,
                    StorePath = DefaultCertificateStorePath(TrustlistType.IssuerHttps, pkiRoot)
                },
                // User trusted & issuer
                TrustedUserCertificates = new CertificateTrustList
                {
                    StoreType = pkiRootType,
                    StorePath = DefaultCertificateStorePath(TrustlistType.TrustedUser, pkiRoot)
                },
                UserIssuerCertificates = new CertificateTrustList
                {
                    StoreType = pkiRootType,
                    StorePath = DefaultCertificateStorePath(TrustlistType.IssuerUser, pkiRoot)
                },
                // rejected store
                RejectedCertificateStore = new CertificateStoreIdentifier
                {
                    StoreType = rejectedRootType,
                    StorePath = DefaultCertificateStorePath(TrustlistType.Rejected, rejectedRoot)
                }
            };
            SetSecureDefaults(ApplicationConfiguration.SecurityConfiguration);

            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderSecurityOptionStores AddSecurityConfigurationStores(
            string subjectName,
            string appRoot,
            string trustedRoot,
            string issuerRoot,
            string rejectedRoot = null)
        {
            string appStoreType = CertificateStoreIdentifier.DetermineStoreType(appRoot);
            string issuerRootType = CertificateStoreIdentifier.DetermineStoreType(issuerRoot);
            string trustedRootType = CertificateStoreIdentifier.DetermineStoreType(trustedRoot);
            rejectedRoot ??= DefaultPKIRoot(null);
            string rejectedRootType = CertificateStoreIdentifier.DetermineStoreType(rejectedRoot);
            ApplicationConfiguration.SecurityConfiguration = new SecurityConfiguration
            {
                // app cert store
                ApplicationCertificate = new CertificateIdentifier
                {
                    StoreType = appStoreType,
                    StorePath = DefaultCertificateStorePath(TrustlistType.Application, appRoot),
                    SubjectName = Utils.ReplaceDCLocalhost(subjectName)
                },
                // App trusted & issuer
                TrustedPeerCertificates = new CertificateTrustList
                {
                    StoreType = trustedRootType,
                    StorePath = DefaultCertificateStorePath(TrustlistType.Trusted, trustedRoot)
                },
                TrustedIssuerCertificates = new CertificateTrustList
                {
                    StoreType = issuerRootType,
                    StorePath = DefaultCertificateStorePath(TrustlistType.Issuer, issuerRoot)
                },
                // rejected store
                RejectedCertificateStore = new CertificateStoreIdentifier
                {
                    StoreType = rejectedRootType,
                    StorePath = DefaultCertificateStorePath(TrustlistType.Rejected, rejectedRoot)
                }
            };
            SetSecureDefaults(ApplicationConfiguration.SecurityConfiguration);

            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderSecurityOptionStores AddSecurityConfigurationUserStore(
            string trustedRoot,
            string issuerRoot)
        {
            string trustedRootType = CertificateStoreIdentifier.DetermineStoreType(trustedRoot);
            string issuerRootType = CertificateStoreIdentifier.DetermineStoreType(issuerRoot);

            // User trusted & issuer
            ApplicationConfiguration.SecurityConfiguration.TrustedUserCertificates
                = new CertificateTrustList
                {
                    StoreType = trustedRootType,
                    StorePath = DefaultCertificateStorePath(TrustlistType.TrustedUser, trustedRoot)
                };
            ApplicationConfiguration.SecurityConfiguration.UserIssuerCertificates
                = new CertificateTrustList
                {
                    StoreType = issuerRootType,
                    StorePath = DefaultCertificateStorePath(TrustlistType.IssuerUser, issuerRoot)
                };
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderSecurityOptionStores AddSecurityConfigurationHttpsStore(
            string trustedRoot,
            string issuerRoot)
        {
            string trustedRootType = CertificateStoreIdentifier.DetermineStoreType(trustedRoot);
            string issuerRootType = CertificateStoreIdentifier.DetermineStoreType(issuerRoot);

            // Https trusted & issuer
            ApplicationConfiguration.SecurityConfiguration.TrustedHttpsCertificates
                = new CertificateTrustList
                {
                    StoreType = trustedRootType,
                    StorePath = DefaultCertificateStorePath(
                        TrustlistType.TrustedHttps,
                        trustedRootType)
                };
            ApplicationConfiguration.SecurityConfiguration.HttpsIssuerCertificates
                = new CertificateTrustList
                {
                    StoreType = issuerRootType,
                    StorePath = DefaultCertificateStorePath(TrustlistType.IssuerHttps, issuerRoot)
                };
            return this;
        }

        /// <inheritdoc/>
        public async Task<ApplicationConfiguration> Create()
        {
            // sanity checks
            if (ApplicationInstance
                    .ApplicationType is ApplicationType.Server or ApplicationType.ClientAndServer &&
                ApplicationConfiguration.ServerConfiguration == null)
            {
                throw new ArgumentException("ApplicationType Server is not configured.");
            }
            if (ApplicationInstance
                    .ApplicationType is ApplicationType.Client or ApplicationType.ClientAndServer &&
                ApplicationConfiguration.ClientConfiguration == null)
            {
                throw new ArgumentException("ApplicationType Client is not configured.");
            }

            // ensure for a user token policy
            if (ApplicationConfiguration.ServerConfiguration?.UserTokenPolicies.Count == 0)
            {
                ApplicationConfiguration.ServerConfiguration.UserTokenPolicies.Add(
                    new UserTokenPolicy(UserTokenType.Anonymous));
            }

            // ensure for secure transport profiles
            if (ApplicationConfiguration.ServerConfiguration?.SecurityPolicies.Count == 0)
            {
                AddSecurityPolicies();
            }

            ApplicationConfiguration.TraceConfiguration?.ApplySettings();

            await ApplicationConfiguration.ValidateAsync(ApplicationInstance.ApplicationType)
                .ConfigureAwait(false);

            await ApplicationConfiguration
                .CertificateValidator.UpdateAsync(ApplicationConfiguration.SecurityConfiguration)
                .ConfigureAwait(false);

            return ApplicationConfiguration;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerSelected AsServer(
            string[] baseAddresses,
            string[] alternateBaseAddresses = null)
        {
            switch (ApplicationInstance.ApplicationType)
            {
                case ApplicationType.Client:
                    ApplicationInstance.ApplicationType = m_typeSelected
                        ? ApplicationType.ClientAndServer
                        : ApplicationType.Server;
                    break;
                case ApplicationType.Server:
                case ApplicationType.ClientAndServer:
                    break;
                default:
                    throw new ArgumentException("Invalid application type for server.");
            }

            m_typeSelected = true;

            // configure a server
            var serverConfiguration = new ServerConfiguration
            {
                // by default disable LDS registration
                MaxRegistrationInterval = 0
            };

            // base addresses
            foreach (string baseAddress in baseAddresses)
            {
                serverConfiguration.BaseAddresses.Add(Utils.ReplaceLocalhost(baseAddress));
            }

            // alternate base addresses
            if (alternateBaseAddresses != null)
            {
                foreach (string alternateBaseAddress in alternateBaseAddresses)
                {
                    serverConfiguration.AlternateBaseAddresses
                        .Add(Utils.ReplaceLocalhost(alternateBaseAddress));
                }
            }

            // add container for policies
            serverConfiguration.SecurityPolicies = [];

            // add user token policy container and Anonymous
            serverConfiguration.UserTokenPolicies = [];

            ApplicationConfiguration.ServerConfiguration = serverConfiguration;

            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerSelected AddUnsecurePolicyNone(
            bool addPolicy = true)
        {
            if (addPolicy)
            {
                ServerSecurityPolicyCollection policies = ApplicationConfiguration
                    .ServerConfiguration
                    .SecurityPolicies;
                InternalAddPolicy(policies, MessageSecurityMode.None, SecurityPolicies.None);
            }
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerSelected AddSignPolicies(
            bool addPolicies = true)
        {
            if (addPolicies)
            {
                AddSecurityPolicies(true, false, false);
            }
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerSelected AddSignAndEncryptPolicies(
            bool addPolicies = true)
        {
            if (addPolicies)
            {
                AddSecurityPolicies(false, false, false);
            }
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerSelected AddEccSignPolicies()
        {
            AddEccSecurityPolicies(true);
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerSelected AddEccSignAndEncryptPolicies()
        {
            AddEccSecurityPolicies(false);
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerSelected AddPolicy(
            MessageSecurityMode securityMode,
            string securityPolicy)
        {
            if (!SecurityPolicies.IsValidSecurityPolicyUri(securityPolicy))
            {
                throw new ArgumentException("Unknown security policy", nameof(securityPolicy));
            }

            if (securityMode == MessageSecurityMode.None ||
                securityPolicy.Equals(SecurityPolicies.None, StringComparison.Ordinal))
            {
                throw new ArgumentException("Use AddUnsecurePolicyNone to add no security policy.");
            }

            InternalAddPolicy(
                ApplicationConfiguration.ServerConfiguration.SecurityPolicies,
                securityMode,
                securityPolicy);
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerSelected AddUserTokenPolicy(
            UserTokenType userTokenType)
        {
            ApplicationConfiguration.ServerConfiguration.UserTokenPolicies
                .Add(new UserTokenPolicy(userTokenType));
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerSelected AddUserTokenPolicy(
            UserTokenPolicy userTokenPolicy)
        {
            if (userTokenPolicy == null)
            {
                throw new ArgumentNullException(nameof(userTokenPolicy));
            }

            ApplicationConfiguration.ServerConfiguration.UserTokenPolicies.Add(userTokenPolicy);
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderSecurityOptions SetApplicationCertificates(
            CertificateIdentifierCollection certIdList)
        {
            ApplicationConfiguration.SecurityConfiguration.ApplicationCertificates = certIdList;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderSecurityOptions SetMaxRejectedCertificates(
            int maxRejectedCertificates)
        {
            ApplicationConfiguration.SecurityConfiguration.MaxRejectedCertificates
                = maxRejectedCertificates;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderSecurityOptions SetAutoAcceptUntrustedCertificates(
            bool autoAccept)
        {
            ApplicationConfiguration.SecurityConfiguration.AutoAcceptUntrustedCertificates
                = autoAccept;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderSecurityOptions SetAddAppCertToTrustedStore(
            bool addToTrustedStore)
        {
            ApplicationConfiguration.SecurityConfiguration.AddAppCertToTrustedStore
                = addToTrustedStore;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderSecurityOptions SetRejectSHA1SignedCertificates(
            bool rejectSHA1Signed)
        {
            ApplicationConfiguration.SecurityConfiguration.RejectSHA1SignedCertificates
                = rejectSHA1Signed;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderSecurityOptions SetRejectUnknownRevocationStatus(
            bool rejectUnknownRevocationStatus)
        {
            ApplicationConfiguration.SecurityConfiguration.RejectUnknownRevocationStatus =
                rejectUnknownRevocationStatus;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderSecurityOptions SetUseValidatedCertificates(
            bool useValidatedCertificates)
        {
            ApplicationConfiguration.SecurityConfiguration.UseValidatedCertificates
                = useValidatedCertificates;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderSecurityOptions SetSuppressNonceValidationErrors(
            bool suppressNonceValidationErrors)
        {
            ApplicationConfiguration.SecurityConfiguration.SuppressNonceValidationErrors =
                suppressNonceValidationErrors;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderSecurityOptions SetSendCertificateChain(
            bool sendCertificateChain)
        {
            ApplicationConfiguration.SecurityConfiguration.SendCertificateChain
                = sendCertificateChain;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderSecurityOptions SetMinimumCertificateKeySize(
            ushort keySize)
        {
            ApplicationConfiguration.SecurityConfiguration.MinimumCertificateKeySize = keySize;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderSecurityOptions AddCertificatePasswordProvider(
            ICertificatePasswordProvider certificatePasswordProvider)
        {
            ApplicationConfiguration.SecurityConfiguration.CertificatePasswordProvider
                = certificatePasswordProvider;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderTransportQuotasSet SetTransportQuotas(
            TransportQuotas transportQuotas)
        {
            ApplicationConfiguration.TransportQuotas = transportQuotas;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderTransportQuotas SetOperationTimeout(
            int operationTimeout)
        {
            ApplicationConfiguration.TransportQuotas.OperationTimeout = operationTimeout;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderTransportQuotas SetMaxStringLength(
            int maxStringLength)
        {
            ApplicationConfiguration.TransportQuotas.MaxStringLength = maxStringLength;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderTransportQuotas SetMaxByteStringLength(
            int maxByteStringLength)
        {
            ApplicationConfiguration.TransportQuotas.MaxByteStringLength = maxByteStringLength;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderTransportQuotas SetMaxArrayLength(int maxArrayLength)
        {
            ApplicationConfiguration.TransportQuotas.MaxArrayLength = maxArrayLength;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderTransportQuotas SetMaxMessageSize(int maxMessageSize)
        {
            ApplicationConfiguration.TransportQuotas.MaxMessageSize = maxMessageSize;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderTransportQuotas SetMaxBufferSize(int maxBufferSize)
        {
            ApplicationConfiguration.TransportQuotas.MaxBufferSize = maxBufferSize;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderTransportQuotas SetChannelLifetime(
            int channelLifetime)
        {
            ApplicationConfiguration.TransportQuotas.ChannelLifetime = channelLifetime;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderTransportQuotas SetSecurityTokenLifetime(
            int securityTokenLifetime)
        {
            ApplicationConfiguration.TransportQuotas.SecurityTokenLifetime = securityTokenLifetime;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderTransportQuotas SetMaxEncodingNestingLevels(
            int maxEncodingNestingLevels)
        {
            ApplicationConfiguration.TransportQuotas.MaxEncodingNestingLevels
                = maxEncodingNestingLevels;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderTransportQuotas SetMaxDecoderRecoveries(
            int maxDecoderRecoveries)
        {
            ApplicationConfiguration.TransportQuotas.MaxDecoderRecoveries = maxDecoderRecoveries;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMinRequestThreadCount(
            int minRequestThreadCount)
        {
            ApplicationConfiguration.ServerConfiguration.MinRequestThreadCount
                = minRequestThreadCount;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMaxRequestThreadCount(
            int maxRequestThreadCount)
        {
            ApplicationConfiguration.ServerConfiguration.MaxRequestThreadCount
                = maxRequestThreadCount;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMaxQueuedRequestCount(
            int maxQueuedRequestCount)
        {
            ApplicationConfiguration.ServerConfiguration.MaxQueuedRequestCount
                = maxQueuedRequestCount;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetDiagnosticsEnabled(
            bool diagnosticsEnabled)
        {
            ApplicationConfiguration.ServerConfiguration.DiagnosticsEnabled = diagnosticsEnabled;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMaxSessionCount(int maxSessionCount)
        {
            ApplicationConfiguration.ServerConfiguration.MaxSessionCount = maxSessionCount;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMaxChannelCount(int maxChannelCount)
        {
            ApplicationConfiguration.ServerConfiguration.MaxChannelCount = maxChannelCount;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMinSessionTimeout(
            int minSessionTimeout)
        {
            ApplicationConfiguration.ServerConfiguration.MinSessionTimeout = minSessionTimeout;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMaxSessionTimeout(
            int maxSessionTimeout)
        {
            ApplicationConfiguration.ServerConfiguration.MaxSessionTimeout = maxSessionTimeout;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMaxBrowseContinuationPoints(
            int maxBrowseContinuationPoints)
        {
            ApplicationConfiguration.ServerConfiguration.MaxBrowseContinuationPoints
                = maxBrowseContinuationPoints;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMaxQueryContinuationPoints(
            int maxQueryContinuationPoints)
        {
            ApplicationConfiguration.ServerConfiguration.MaxQueryContinuationPoints
                = maxQueryContinuationPoints;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMaxHistoryContinuationPoints(
            int maxHistoryContinuationPoints)
        {
            ApplicationConfiguration.ServerConfiguration.MaxHistoryContinuationPoints
                = maxHistoryContinuationPoints;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMaxRequestAge(int maxRequestAge)
        {
            ApplicationConfiguration.ServerConfiguration.MaxRequestAge = maxRequestAge;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMinPublishingInterval(
            int minPublishingInterval)
        {
            ApplicationConfiguration.ServerConfiguration.MinPublishingInterval
                = minPublishingInterval;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMaxPublishingInterval(
            int maxPublishingInterval)
        {
            ApplicationConfiguration.ServerConfiguration.MaxPublishingInterval
                = maxPublishingInterval;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetPublishingResolution(
            int publishingResolution)
        {
            ApplicationConfiguration.ServerConfiguration.PublishingResolution
                = publishingResolution;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMaxSubscriptionLifetime(
            int maxSubscriptionLifetime)
        {
            ApplicationConfiguration.ServerConfiguration.MaxSubscriptionLifetime
                = maxSubscriptionLifetime;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMaxMessageQueueSize(
            int maxMessageQueueSize)
        {
            ApplicationConfiguration.ServerConfiguration.MaxMessageQueueSize = maxMessageQueueSize;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMaxNotificationQueueSize(
            int maxNotificationQueueSize)
        {
            ApplicationConfiguration.ServerConfiguration.MaxNotificationQueueSize
                = maxNotificationQueueSize;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMaxNotificationsPerPublish(
            int maxNotificationsPerPublish)
        {
            ApplicationConfiguration.ServerConfiguration.MaxNotificationsPerPublish
                = maxNotificationsPerPublish;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMinMetadataSamplingInterval(
            int minMetadataSamplingInterval)
        {
            ApplicationConfiguration.ServerConfiguration.MinMetadataSamplingInterval
                = minMetadataSamplingInterval;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetAvailableSamplingRates(
            SamplingRateGroupCollection availableSampleRates)
        {
            ApplicationConfiguration.ServerConfiguration.AvailableSamplingRates
                = availableSampleRates;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetRegistrationEndpoint(
            EndpointDescription registrationEndpoint)
        {
            ApplicationConfiguration.ServerConfiguration.RegistrationEndpoint
                = registrationEndpoint;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMaxRegistrationInterval(
            int maxRegistrationInterval)
        {
            ApplicationConfiguration.ServerConfiguration.MaxRegistrationInterval
                = maxRegistrationInterval;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetNodeManagerSaveFile(
            string nodeManagerSaveFile)
        {
            ApplicationConfiguration.ServerConfiguration.NodeManagerSaveFile = nodeManagerSaveFile;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMinSubscriptionLifetime(
            int minSubscriptionLifetime)
        {
            ApplicationConfiguration.ServerConfiguration.MinSubscriptionLifetime
                = minSubscriptionLifetime;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMaxPublishRequestCount(
            int maxPublishRequestCount)
        {
            ApplicationConfiguration.ServerConfiguration.MaxPublishRequestCount
                = maxPublishRequestCount;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMaxSubscriptionCount(
            int maxSubscriptionCount)
        {
            ApplicationConfiguration.ServerConfiguration.MaxSubscriptionCount
                = maxSubscriptionCount;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMaxEventQueueSize(
            int setMaxEventQueueSize)
        {
            ApplicationConfiguration.ServerConfiguration.MaxEventQueueSize = setMaxEventQueueSize;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions AddServerProfile(string serverProfile)
        {
            ApplicationConfiguration.ServerConfiguration.ServerProfileArray.Add(serverProfile);
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetShutdownDelay(int shutdownDelay)
        {
            ApplicationConfiguration.ServerConfiguration.ShutdownDelay = shutdownDelay;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions AddServerCapabilities(
            string serverCapability)
        {
            ApplicationConfiguration.ServerConfiguration.ServerCapabilities.Add(serverCapability);
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetSupportedPrivateKeyFormats(
            StringCollection supportedPrivateKeyFormats)
        {
            ApplicationConfiguration.ServerConfiguration.SupportedPrivateKeyFormats
                = supportedPrivateKeyFormats;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMaxTrustListSize(
            int maxTrustListSize)
        {
            ApplicationConfiguration.ServerConfiguration.MaxTrustListSize = maxTrustListSize;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMultiCastDnsEnabled(
            bool multiCastDnsEnabled)
        {
            ApplicationConfiguration.ServerConfiguration.MultiCastDnsEnabled = multiCastDnsEnabled;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetReverseConnect(
            ReverseConnectServerConfiguration reverseConnectConfiguration)
        {
            ApplicationConfiguration.ServerConfiguration.ReverseConnect
                = reverseConnectConfiguration;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetOperationLimits(
            OperationLimits operationLimits)
        {
            ApplicationConfiguration.ServerConfiguration.OperationLimits = operationLimits;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetAuditingEnabled(
            bool auditingEnabled)
        {
            ApplicationConfiguration.ServerConfiguration.AuditingEnabled = auditingEnabled;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetHttpsMutualTls(
            bool mutualTlsEnabeld)
        {
            ApplicationConfiguration.ServerConfiguration.HttpsMutualTls = mutualTlsEnabeld;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderClientOptions SetDefaultSessionTimeout(
            int defaultSessionTimeout)
        {
            ApplicationConfiguration.ClientConfiguration.DefaultSessionTimeout
                = defaultSessionTimeout;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderClientOptions AddWellKnownDiscoveryUrls(
            string wellKnownDiscoveryUrl)
        {
            ApplicationConfiguration.ClientConfiguration.WellKnownDiscoveryUrls
                .Add(wellKnownDiscoveryUrl);
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderClientOptions AddDiscoveryServer(
            EndpointDescription discoveryServer)
        {
            ApplicationConfiguration.ClientConfiguration.DiscoveryServers.Add(discoveryServer);
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderClientOptions SetEndpointCacheFilePath(
            string endpointCacheFilePath)
        {
            ApplicationConfiguration.ClientConfiguration.EndpointCacheFilePath
                = endpointCacheFilePath;
            return this;
        }

        /// <inheritdoc/>
        IApplicationConfigurationBuilderClientOptions IApplicationConfigurationBuilderClientOptions.SetMinSubscriptionLifetime(
            int minSubscriptionLifetime)
        {
            ApplicationConfiguration.ClientConfiguration.MinSubscriptionLifetime
                = minSubscriptionLifetime;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderClientOptions SetReverseConnect(
            ReverseConnectClientConfiguration reverseConnect)
        {
            ApplicationConfiguration.ClientConfiguration.ReverseConnect = reverseConnect;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderClientOptions SetClientOperationLimits(
            OperationLimits operationLimits)
        {
            ApplicationConfiguration.ClientConfiguration.OperationLimits = operationLimits;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderTraceConfiguration SetOutputFilePath(
            string outputFilePath)
        {
            ApplicationConfiguration.TraceConfiguration.OutputFilePath = outputFilePath;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderTraceConfiguration SetDeleteOnLoad(bool deleteOnLoad)
        {
            ApplicationConfiguration.TraceConfiguration.DeleteOnLoad = deleteOnLoad;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderTraceConfiguration SetTraceMasks(int traceMasks)
        {
            ApplicationConfiguration.TraceConfiguration.TraceMasks = traceMasks;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderExtension AddExtension<T>(
            XmlQualifiedName elementName,
            object value)
        {
            ApplicationConfiguration.UpdateExtension<T>(elementName, value);
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetDurableSubscriptionsEnabled(
            bool durableSubscriptionsEnabled)
        {
            ApplicationConfiguration.ServerConfiguration.DurableSubscriptionsEnabled
                = durableSubscriptionsEnabled;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMaxDurableNotificationQueueSize(
            int maxDurableNotificationQueueSize)
        {
            ApplicationConfiguration.ServerConfiguration.MaxDurableNotificationQueueSize =
                maxDurableNotificationQueueSize;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMaxDurableEventQueueSize(
            int maxDurableEventQueueSize)
        {
            ApplicationConfiguration.ServerConfiguration.MaxDurableEventQueueSize
                = maxDurableEventQueueSize;
            return this;
        }

        /// <inheritdoc/>
        public IApplicationConfigurationBuilderServerOptions SetMaxDurableSubscriptionLifetime(
            int maxDurableSubscriptionLifetimeInHours)
        {
            ApplicationConfiguration.ServerConfiguration.MaxDurableSubscriptionLifetimeInHours =
                maxDurableSubscriptionLifetimeInHours;
            return this;
        }

        /// <summary>
        /// Create ApplicationCertificates from a PKI root.
        /// </summary>
        /// <param name="subjectName">The subject name.</param>
        /// <param name="storeType">The cert store type: ex: "Directory"</param>
        /// <param name="storePath">The PKI root.</param>
        /// <returns>The application certificates.</returns>
        public static CertificateIdentifierCollection CreateDefaultApplicationCertificates(
            string subjectName,
            string storeType = null,
            string storePath = null)
        {
            var certificateIdentifiers = new CertificateIdentifierCollection
            {
                new CertificateIdentifier
                {
                    StoreType = storeType,
                    StorePath = storePath,
                    SubjectName = subjectName,
                    CertificateType = ObjectTypeIds.RsaSha256ApplicationCertificateType
                }
            };
#if ECC_SUPPORT
            certificateIdentifiers.AddRange(
                [
                    new CertificateIdentifier
                    {
                        StoreType = storeType,
                        StorePath = storePath,
                        SubjectName = subjectName,
                        CertificateType = ObjectTypeIds.EccNistP256ApplicationCertificateType
                    },
                    new CertificateIdentifier
                    {
                        StoreType = storeType,
                        StorePath = storePath,
                        SubjectName = subjectName,
                        CertificateType = ObjectTypeIds.EccNistP384ApplicationCertificateType
                    }
                ]);

            if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                certificateIdentifiers.AddRange(
                    [
                        new CertificateIdentifier
                        {
                            StoreType = storeType,
                            StorePath = storePath,
                            SubjectName = subjectName,
                            CertificateType = ObjectTypeIds
                                .EccBrainpoolP256r1ApplicationCertificateType
                        },
                        new CertificateIdentifier
                        {
                            StoreType = storeType,
                            StorePath = storePath,
                            SubjectName = subjectName,
                            CertificateType = ObjectTypeIds
                                .EccBrainpoolP384r1ApplicationCertificateType
                        }
                    ]);
            }
#endif
            return certificateIdentifiers;
        }

        /// <summary>
        /// Internal enumeration of supported trust lists.
        /// </summary>
        private enum TrustlistType
        {
            Application,
            Trusted,
            Issuer,
            TrustedHttps,
            IssuerHttps,
            TrustedUser,
            IssuerUser,
            Rejected
        }

        /// <summary>
        /// Return the default PKI root path if root is unspecified, directory or X509Store.
        /// </summary>
        /// <param name="root">A real root path or the store type.</param>
        private static string DefaultPKIRoot(string root)
        {
            if (root == null ||
                root.Equals(CertificateStoreType.Directory, StringComparison.OrdinalIgnoreCase))
            {
                return CertificateStoreIdentifier.DefaultPKIRoot;
            }
            else if (root.Equals(
                CertificateStoreType.X509Store,
                StringComparison.OrdinalIgnoreCase))
            {
                return CertificateStoreIdentifier.CurrentUser;
            }
            return root;
        }

        /// <summary>
        /// Determine the default store path for a given trust list type.
        /// </summary>
        /// <param name="trustListType">The trust list type.</param>
        /// <param name="pkiRoot">A PKI root for which the store path is needed.</param>
        /// <exception cref="NotSupportedException"></exception>
        private static string DefaultCertificateStorePath(
            TrustlistType trustListType,
            string pkiRoot)
        {
            string pkiRootType = CertificateStoreIdentifier.DetermineStoreType(pkiRoot);
            if (pkiRootType.Equals(
                CertificateStoreType.Directory,
                StringComparison.OrdinalIgnoreCase))
            {
                string leafPath = string.Empty;
                // see https://reference.opcfoundation.org/v104/GDS/docs/F.1/
                switch (trustListType)
                {
                    case TrustlistType.Application:
                        leafPath = "own";
                        break;
                    case TrustlistType.Trusted:
                        leafPath = "trusted";
                        break;
                    case TrustlistType.Issuer:
                        leafPath = "issuer";
                        break;
                    case TrustlistType.TrustedHttps:
                        leafPath = "trustedHttps";
                        break;
                    case TrustlistType.IssuerHttps:
                        leafPath = "issuerHttps";
                        break;
                    case TrustlistType.TrustedUser:
                        leafPath = "trustedUser";
                        break;
                    case TrustlistType.IssuerUser:
                        leafPath = "issuerUser";
                        break;
                    case TrustlistType.Rejected:
                        leafPath = "rejected";
                        break;
                }
                // Caller may have already provided the leaf path, then no need to add.
                int startIndex = pkiRoot.Length - leafPath.Length;
                char lastChar = pkiRoot[^1];
                if (lastChar == Path.DirectorySeparatorChar ||
                    lastChar == Path.AltDirectorySeparatorChar)
                {
                    startIndex--;
                }
                if (startIndex > 0 &&
                    pkiRoot
                        .Substring(startIndex, leafPath.Length)
                        .Equals(leafPath, StringComparison.OrdinalIgnoreCase))
                {
                    return pkiRoot;
                }
                return Path.Combine(pkiRoot, leafPath);
            }
            else if (pkiRootType.Equals(
                CertificateStoreType.X509Store,
                StringComparison.OrdinalIgnoreCase))
            {
                switch (trustListType)
                {
                    case TrustlistType.Application:
#if !NETFRAMEWORK
                        if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) &&
                            pkiRoot.StartsWith(
                                CertificateStoreIdentifier.CurrentUser,
                                StringComparison.OrdinalIgnoreCase))
                        {
                            return pkiRoot + "My";
                        }
#endif
                        return pkiRoot + "UA_MachineDefault";
                    case TrustlistType.Trusted:
                        return pkiRoot + "UA_Trusted";
                    case TrustlistType.Issuer:
                        return pkiRoot + "UA_Issuer";
                    case TrustlistType.TrustedHttps:
                        return pkiRoot + "UA_Trusted_Https";
                    case TrustlistType.IssuerHttps:
                        return pkiRoot + "UA_Issuer_Https";
                    case TrustlistType.TrustedUser:
                        return pkiRoot + "UA_Trusted_User";
                    case TrustlistType.IssuerUser:
                        return pkiRoot + "UA_Issuer_User";
                    case TrustlistType.Rejected:
                        return pkiRoot + "UA_Rejected";
                }
            }
            else
            {
                // return custom root store
                return pkiRoot;
            }
            throw new NotSupportedException("Unsupported store type.");
        }

        /// <summary>
        /// Add specified groups of security policies and security modes.
        /// </summary>
        /// <param name="includeSign">Include the Sign only policies.</param>
        /// <param name="deprecated">Include the deprecated policies.</param>
        /// <param name="policyNone">Include policy 'None'. (no security!)</param>
        private void AddSecurityPolicies(
            bool includeSign = false,
            bool deprecated = false,
            bool policyNone = false)
        {
            // create list of supported policies
            System.Collections.Generic.List<string> defaultPolicyUris = [.. SecurityPolicies
                .GetDefaultUris()];
            if (deprecated)
            {
                defaultPolicyUris.AddRange(SecurityPolicies.GetDefaultDeprecatedUris());
            }

            foreach (MessageSecurityMode securityMode in typeof(MessageSecurityMode)
                .GetEnumValues())
            {
                ServerSecurityPolicyCollection policies = ApplicationConfiguration
                    .ServerConfiguration
                    .SecurityPolicies;
                if (policyNone && securityMode == MessageSecurityMode.None)
                {
                    InternalAddPolicy(policies, MessageSecurityMode.None, SecurityPolicies.None);
                }
                else if (securityMode >= MessageSecurityMode.SignAndEncrypt ||
                    (includeSign && securityMode == MessageSecurityMode.Sign))
                {
                    foreach (string policyUri in defaultPolicyUris)
                    {
                        InternalAddPolicy(policies, securityMode, policyUri);
                    }
                }
            }
        }

        /// <summary>
        /// Add default Ecc policies.
        /// </summary>
        private void AddEccSecurityPolicies(bool sign = false)
        {
            // create list of supported policies
            string[] defaultPolicyUris = SecurityPolicies.GetDefaultEccUris();
            MessageSecurityMode securityMode = sign
                ? MessageSecurityMode.Sign
                : MessageSecurityMode.SignAndEncrypt;
            {
                ServerSecurityPolicyCollection policies = ApplicationConfiguration
                    .ServerConfiguration
                    .SecurityPolicies;
                foreach (string policyUri in defaultPolicyUris)
                {
                    InternalAddPolicy(policies, securityMode, policyUri);
                }
            }
        }

        /// <summary>
        /// Set secure defaults for flags.
        /// </summary>
        private static void SetSecureDefaults(SecurityConfiguration securityConfiguration)
        {
            // ensure secure default settings
            securityConfiguration.AutoAcceptUntrustedCertificates = false;
            securityConfiguration.AddAppCertToTrustedStore = false;
            securityConfiguration.RejectSHA1SignedCertificates = true;
            securityConfiguration.RejectUnknownRevocationStatus = true;
            securityConfiguration.SuppressNonceValidationErrors = false;
            securityConfiguration.SendCertificateChain = true;
            securityConfiguration.MinimumCertificateKeySize = CertificateFactory.DefaultKeySize;
            securityConfiguration.MaxRejectedCertificates = 5;
        }

        /// <summary>
        /// Add security policy if it doesn't exist yet.
        /// </summary>
        /// <param name="policies">The collection to which the policies are added.</param>
        /// <param name="securityMode">The message security mode.</param>
        /// <param name="policyUri">The security policy Uri.</param>
        /// <exception cref="ArgumentException"><paramref name="securityMode"/></exception>
        private static bool InternalAddPolicy(
            ServerSecurityPolicyCollection policies,
            MessageSecurityMode securityMode,
            string policyUri)
        {
            if (securityMode == MessageSecurityMode.Invalid)
            {
                throw new ArgumentException("Invalid security mode selected", nameof(securityMode));
            }

            var newPolicy = new ServerSecurityPolicy
            {
                SecurityMode = securityMode,
                SecurityPolicyUri = policyUri
            };
            if (policies.Find(s =>
                    s.SecurityMode == newPolicy.SecurityMode &&
                    string.Equals(
                        s.SecurityPolicyUri,
                        newPolicy.SecurityPolicyUri,
                        StringComparison.Ordinal)
                ) == null)
            {
                policies.Add(newPolicy);
                return true;
            }
            return false;
        }

        private bool m_typeSelected;
    }
}
